package com.googlecode.gwtbb.server.intermediate;

import com.googlecode.gwtbb.client.shared.util.StringUtils;
import org.apache.commons.fileupload.FileItem;

import javax.servlet.ServletException;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @author Abraham Grief
 * @version $Id$
 * @since Aug 2, 2008
 */
public abstract class FileOrganizer {
	private String fileBaseDir;
	private String tempFilePrefix;
	private String tempFileSuffix;
	private String tempFileDir;

	private final ThreadLocal<SimpleDateFormat> pathFormat = new ThreadLocal<SimpleDateFormat>() {
		protected SimpleDateFormat initialValue() {
			return new SimpleDateFormat("yyyy" + File.separator + "MM" + File.separator + "dd");
		}
	};

	public String getFileBaseDir() {
		return fileBaseDir;
	}

	public void setFileBaseDir(String fileBaseDir) {
		this.fileBaseDir = fileBaseDir;
	}

	public String getTempFileDir() {
		return tempFileDir;
	}

	public void setTempFileDir(String tempFileDir) {
		this.tempFileDir = tempFileDir;
	}

	public String getTempFilePrefix() {
		return tempFilePrefix;
	}

	public void setTempFilePrefix(String tempFilePrefix) {
		this.tempFilePrefix = tempFilePrefix;
	}

	public String getTempFileSuffix() {
		return tempFileSuffix;
	}

	public void setTempFileSuffix(String tempFileSuffix) {
		this.tempFileSuffix = tempFileSuffix;
	}

	public boolean fileExists(String pathName) {
		pathName = ensureSeparator(pathName);
		return new File(fileBaseDir + File.separator + pathName).exists();
	}

	public abstract String getAdditionalInfo(File file);

	public String getDirPath() {
		return fileBaseDir + File.separator + pathFormat.get().format(new Date());
	}

	public abstract String getFileName(String clientFileName, File tmpFile) throws IOException;

	public String getOrganizedPath(File organizedFile) {
		return organizedFile.getPath().substring(fileBaseDir.length() + 1);
	}

	/**
	 * @param clientFileName file name on the client's system
	 * @param tmpFile        the temporary location of the file
	 * @return the full filesystem path of the permanent location of the file
	 * @throws java.io.IOException if we can't read valid data from the tmpFile
	 */
	public String getPath(String clientFileName, File tmpFile) throws IOException {
		return getDirPath() + File.separator + getFileName(clientFileName, tmpFile);
	}

	public File writeFile(FileItem fileItem) throws ServletException, IOException {
		File file;
		try {
			File tempDir = new File(tempFileDir);
			if (!tempDir.exists())
				throw new IOException("tempFileDir does not exist: " + tempFileDir);
			File tmpFile = File.createTempFile(tempFilePrefix, tempFilePrefix, tempDir);
			fileItem.write(tmpFile);

			String path = getPath(fileItem.getName(), tmpFile);

			// ensure parent directory exists
			File dir = new File(path.substring(0, path.lastIndexOf(File.separator)));
			dir.mkdirs();
			file = new File(path);
			if (!tmpFile.renameTo(file))
				throw new IOException("could not rename tmpFile: " + tmpFile.getPath() + " to: " + file.getPath());
		} catch (IOException e) {
			throw e;
		} catch (Exception e) {
			throw new ServletException(e);
		}
		return file;
	}

	protected String ensureSeparator(String pathName) {
		if (File.separatorChar != StringUtils.URL_SEPARATOR_CHAR)
			return pathName.replace(StringUtils.URL_SEPARATOR_CHAR, File.separatorChar);
		return pathName;
	}
}
